<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>拖拽排序数组</title>
</head>

<body>


    原文链接：https://juejin.cn/post/7174065763865591821


    <!--为了可以实现拖拽操作，我们必须给每个元素设置 draggable="true"-->
    <ul class="list" v-model="checkList">
        <li draggable="true" value="1">1</li>
        <li draggable="true" value="2">2</li>
        <li draggable="true" value="3">3</li>
        <li draggable="true" value="4">4</li>
        <li draggable="true" value="5">5</li>
    </ul>
    <ul>
        您的数据排序是：<h2 id="view"></h2>
    </ul>

    <script>



        const forli = () => {

            var arr = document.getElementsByTagName('li'), temp = [];
            for (var i = 0; i < arr.length; i++) {
                temp.push(arr[i].innerHTML)
                div = document.getElementById("view");
                div.innerHTML = JSON.stringify(temp);
                //div.innerHTML = temp;
            }



        }

        forli();//先执行一遍








        //实现拖出去的元素，原位置样式变为透明虚线
        //实现拖动到其他元素上时，列表顺序发生改变


        let list = document.querySelector('.list')
        let currentLi      // 记录拖拽元素



        //用事件委托，监听 "dragstart" 事件，给拖动的元素添加类名，修改样式，这里会出现奇怪的一幕就是，拖动的样式和原来的样式同时变成了透明。
        //跟随鼠标拖动的元素的样式在拖动的那一刻是原始元素的样式，所以也会添加"moving"， 那么在这里我们加一个异步
        list.addEventListener('dragstart', (e) => {
            e.dataTransfer.effectAllowed = 'move'// 拖动样式改为 "move"
            currentLi = e.target
            //异步
            setTimeout(() => {
                currentLi.classList.add('moving')
            })
        })


        //需要在拖动的过程中对列表的元素进行重新的排序
        //Node.insertBefore()：方法在参考节点之前插入一个拥有指定父节点的子节点

        list.addEventListener('dragenter', (e) => {
            e.preventDefault()  // 阻止默认事件
            if (e.target === currentLi || e.target === list) {   // 当移动到当前拖动元素，或者父元素上面我们不做操作
                return
            }
            let liArray = Array.from(list.childNodes)
            let currentIndex = liArray.indexOf(currentLi)   // 获取到拖动元素的下标
            let targetindex = liArray.indexOf(e.target)     // 获取到目标元素的下标

            if (currentIndex < targetindex) {
                list.insertBefore(currentLi, e.target.nextElementSibling)
            } else {
                list.insertBefore(currentLi, e.target)
            }
        })

        //需要在拖拽结束将元素的moving类名移除,以及阻止拖拽到一个目标上的默认事件（否则会出现禁止）

        list.addEventListener('dragover', (e) => {
            e.preventDefault(), forli()
        })
        list.addEventListener('dragend', (e) => {
            currentLi.classList.remove('moving')
        })




    </script>


    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        ul {
            margin: 200px auto;
            width: 200px;
            list-style-type: none;
        }

        li {
            margin: 5px;
            text-align: center;
            width: 200px;
            height: 30px;
            background: skyblue;
        }

        .list .moving {
            background: transparent;
            color: transparent;
            border: 1px dashed #ccc;
        }
    </style>
</body>

</html>